/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * @file rw_utils.c
 * @brief 读卡相关工具函数
 */

#include "nci_feature.h"
#if IS_FEATURE_ON(NCI_FEATURE_RW)

#include "rw_utils.h"
#include "nci_data.h"
#include "nfc_hex_utils.h"
#include "nfa_rw.h"

#define MEMCPY(_dst, _dst_size, _src, _src_len) if (!osi_memcpy_s(_dst, _dst_size, _src, _src_len)) { \
    NFCLOG_E("memcpy failed"); \
    return NCI_STATUS_EXT_COPY_FAILED; \
}

static void add_sak(tNCI_RW_TAG *p_tag, uint8_t sak) {
    uint8_t merge_sak = sak;
    for (size_t i = 0; i < p_tag->tech_size; i++) {
        tNCI_RW_TAG_TYPE tag_type = p_tag->tag_types[i];
        if (tag_type != NCI_RW_TAG_TYPE_A && tag_type != NCI_RW_TAG_TYPE_M1) {
            continue;
        }
        tNCI_RW_ACT_DATA *p_act = &p_tag->act_data[i];
        if (p_act->len != 1) {
            continue;
        }
        merge_sak = p_act->data[0] | sak;
        p_act->data[0] = merge_sak;
    }

    p_tag->act_data[p_tag->tech_size].len = 1;
    p_tag->act_data[p_tag->tech_size].data[0] = merge_sak;

    NFCLOG_I("add sak=0x%02X, merge_sak=0x%02X", sak, merge_sak);
}

static tNCI_STATUS add_tag_type(tNCI_RW_TAG *p_tag, tNCI_RF_INTF_ACTIVATED_PARAMS *p_params, tNCI_RW_TAG_TYPE tag_type, tNCI_RF_INTERFACE interface, bool is_current) {
    p_tag->disc_ids[p_tag->tech_size] = p_params->id;
    p_tag->protocols[p_tag->tech_size] = p_params->protocol;
    p_tag->tag_types[p_tag->tech_size] = tag_type;
    p_tag->interfaces[p_tag->tech_size] = interface;
    MEMCPY(&p_tag->tech_params[p_tag->tech_size], sizeof(tNCI_RF_TECH_PARAMS), &p_params->tech_params, sizeof(tNCI_RF_TECH_PARAMS));
    MEMCPY(&p_tag->act_params[p_tag->tech_size], sizeof(tNCI_RF_ACT_PARAMS), &p_params->act_params, sizeof(tNCI_RF_ACT_PARAMS));
    tNCI_RW_POLL_DATA *p_poll = &p_tag->poll_data[p_tag->tech_size];
    tNCI_RW_ACT_DATA *p_act = &p_tag->act_data[p_tag->tech_size];
    if (tag_type == NCI_RW_TAG_TYPE_A || tag_type == NCI_RW_TAG_TYPE_MUL || tag_type == NCI_RW_TAG_TYPE_M1) {
        // poll data
        MEMCPY(p_poll->data, NCI_RW_MAX_POLL_DATA_LEN, p_params->tech_params.pa.sens_res, NCI_SENS_RES_LEN)
        p_poll->len = NCI_SENS_RES_LEN;
        // act data
        add_sak(p_tag, p_params->tech_params.pa.sel_res);
    } else if (tag_type == NCI_RW_TAG_TYPE_B) {
        MEMCPY(p_poll->data, NCI_RW_MAX_POLL_DATA_LEN, &p_params->tech_params.pb.sensb_res[5], 7);
        p_poll->len = 7;
    } else if (tag_type == NCI_RW_TAG_TYPE_F) {
        MEMCPY(p_poll->data, NCI_RW_MAX_POLL_DATA_LEN, &p_params->tech_params.pf.sensf_res[8], 8);
        p_poll->len = 8;
    } else if (tag_type == NCI_RW_TAG_TYPE_V) {
        p_poll->data[0] = p_params->tech_params.pv.res_flag;
        p_poll->data[1] = p_params->tech_params.pv.dsfid;
        p_poll->len = 2;
    } else if (tag_type == NCI_RW_TAG_TYPE_ISO_DEP) {
        if (p_params->activation_tech_mode == NCI_RF_TECH_A_PASSIVE_POLL_MODE) {
            // TypeA + IsoDep
            MEMCPY(p_poll->data, NCI_RW_MAX_POLL_DATA_LEN, p_params->tech_params.pa.sens_res, NCI_SENS_RES_LEN)
            p_poll->len = NCI_SENS_RES_LEN;
            MEMCPY(p_act->data, NCI_RW_MAX_ACT_DATA_LEN, p_params->act_params.pa_iso_dep.his_bytes, p_params->act_params.pa_iso_dep.his_bytes_len);
            p_act->len = p_params->act_params.pa_iso_dep.his_bytes_len;
        } else if (p_params->activation_tech_mode == NCI_RF_TECH_B_PASSIVE_POLL_MODE) {
            // TypeB + IsoDep
            MEMCPY(p_act->data, NCI_RW_MAX_ACT_DATA_LEN, p_params->act_params.pb_iso_dep.hi_layer_bytes, p_params->act_params.pb_iso_dep.hi_layer_len);
            p_act->len = p_params->act_params.pb_iso_dep.hi_layer_len;
        }
    } else {
        NFCLOG_W("no poll data or act data for tech type: %d", tag_type);
    }
    if (is_current) {
        p_tag->index = p_tag->tech_size;
    }
    p_tag->tech_size++;
    return NCI_STATUS_OK;
}

static tNCI_STATUS add_uid(tNCI_RW_TAG *p_tag, tNCI_RF_INTF_ACTIVATED_PARAMS *p_params) {
    if (p_params->activation_tech_mode == NCI_RF_TECH_A_PASSIVE_POLL_MODE) {
        MEMCPY(p_tag->uid, NCI_RW_MAX_UID_LEN, p_params->tech_params.pa.nfcid1, p_params->tech_params.pa.nfcid1_len);
        p_tag->uid_len = p_params->tech_params.pa.nfcid1_len;
    } else if (p_params->activation_tech_mode == NCI_RF_TECH_B_PASSIVE_POLL_MODE) {
        MEMCPY(p_tag->uid, NCI_RW_MAX_UID_LEN, &p_params->tech_params.pb.sensb_res[0], 4);
        p_tag->uid_len = 4;
    } else if (p_params->activation_tech_mode == NCI_RF_TECH_F_PASSIVE_POLL_MODE) {
        MEMCPY(p_tag->uid, NCI_RW_MAX_UID_LEN, &p_params->tech_params.pf.sensf_res[0], 8);
        p_tag->uid_len = 8;
    } else if (p_params->activation_tech_mode == NCI_RF_TECH_V_PASSIVE_POLL_MODE) {
        MEMCPY(p_tag->uid, NCI_RW_MAX_UID_LEN, p_params->tech_params.pv.uid, NCI_TECH_PARAM_PV_UID_LEN);
        p_tag->uid_len = NCI_TECH_PARAM_PV_UID_LEN;
    } else {
        NFCLOG_E("Invalid RF tech mode: 0x%02X", p_params->activation_tech_mode);
        return NCI_STATUS_EXT_FAILED;
    }
    return NCI_STATUS_OK;
}

/**
 * @brief 从NCI_RF_INTF_ACTIVATED_PARAMS中获取tag类型并添加到p_tag中
 *
 * @param p_tag 需要被添加的tag指针
 * @param p_params 需要被添加的激活参数
 *
 * @return 成功返回NCI_STATUS_OK，失败返回其他值
 */
tNCI_STATUS rw_utils_add_tech(tNCI_RW_TAG *p_tag, tNCI_RF_INTF_ACTIVATED_PARAMS *p_params) {
    if (!p_tag || !p_params) {
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    tNCI_STATUS ret = NCI_STATUS_FAILED;
    if (p_params->protocol == NCI_RF_PROTOCOL_T1T) {
        ret = add_tag_type(p_tag, p_params, NCI_RW_TAG_TYPE_A, p_params->interface, true);
    } else if (p_params->protocol == NCI_RF_PROTOCOL_T2T) {
        tNCI_RF_TECH_PARAMS *tech_params = &p_params->tech_params;
        ret = add_tag_type(p_tag, p_params, NCI_RW_TAG_TYPE_A, p_params->interface, false);
        if (ret != NCI_STATUS_OK) {
            return ret;
        }
        if (tech_params->pa.nfcid1[0] == 0x04 && tech_params->pa.sel_res == 0) {
            ret = add_tag_type(p_tag, p_params, NCI_RW_TAG_TYPE_MUL, p_params->interface, true);
        }
    } else if (p_params->protocol == NCI_RF_PROTOCOL_T3T) {
        ret = add_tag_type(p_tag, p_params,  NCI_RW_TAG_TYPE_F, p_params->interface, true);
    } else if (p_params->protocol == NCI_RF_PROTOCOL_ISO_DEP) {
        ret = add_tag_type(p_tag, p_params, NCI_RW_TAG_TYPE_ISO_DEP, p_params->interface, true);
        if (ret != NCI_STATUS_OK) {
            return ret;
        }
        if (p_params->activation_tech_mode == NCI_RF_TECH_A_PASSIVE_POLL_MODE) {
            ret = add_tag_type(p_tag, p_params, NCI_RW_TAG_TYPE_A, NCI_RF_INTERFACE_FRAME, false);
        } else if (p_params->activation_tech_mode == NCI_RF_TECH_B_PASSIVE_POLL_MODE) {
            ret = add_tag_type(p_tag, p_params, NCI_RW_TAG_TYPE_B, NCI_RF_INTERFACE_FRAME, false);
        }
    } else if (p_params->protocol == NCI_RF_PROTOCOL_T5T) {
        ret = add_tag_type(p_tag, p_params, NCI_RW_TAG_TYPE_V, p_params->interface, true);
    } else if (p_params->protocol == NCI_RF_PROTOCOL_KOVIO) {
        ret = add_tag_type(p_tag, p_params, NCI_RW_TAG_TYPE_KOVIO, p_params->interface, true);
    } else if (p_params->protocol == NCI_RF_PROTOCOL_M1) {
        ret = add_tag_type(p_tag, p_params, NCI_RW_TAG_TYPE_A, NCI_RF_INTERFACE_FRAME, false);
        if (ret != NCI_STATUS_OK) {
            return ret;
        }
        ret = add_tag_type(p_tag, p_params, NCI_RW_TAG_TYPE_M1, p_params->interface, true);
    } else if (p_params->protocol == NCI_RF_PROTOCOL_UNDETERMINED && p_params->activation_tech_mode == NCI_RF_TECH_B_PASSIVE_POLL_MODE) {
        // 身份证
        ret = add_tag_type(p_tag, p_params, NCI_RW_TAG_TYPE_B, p_params->interface, true);
    } else {
        NFCLOG_E("Unknown protocol: %d", p_params->protocol);
    }

    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("Failed to add tech type, ret=%d", ret);
    }

    return ret;
}
/**
 * @brief 通过激活参数创建tag
 *
 * @param p_params 激活参数
 *
 * @return 创建成功返回tag指针，失败返回NULL
 */
tNCI_RW_TAG *rw_utils_create_tag(tNCI_RF_INTF_ACTIVATED_PARAMS *p_params) {
    tNCI_RW_TAG *p_tag = (tNCI_RW_TAG *)osi_calloc(sizeof(tNCI_RW_TAG));
    if (!p_tag) {
        NFCLOG_E("Failed to allocate memory");
        return NULL;
    }

    p_tag->index = 0;
    tNCI_STATUS ret = add_uid(p_tag, p_params);
    if (ret != NCI_STATUS_OK) {
        osi_free(p_tag);
        NFCLOG_E("Failed to add uid");
        return NULL;
    }
    ret = rw_utils_add_tech(p_tag, p_params);
    if (ret != NCI_STATUS_OK) {
        osi_free(p_tag);
        NFCLOG_E("Failed to add tech");
        return NULL;
    }
    return p_tag;
}
/**
 * @brief 通过协议获取rf接口
 *
 * @param protocol 协议类型
 *
 * @return 返回rf接口类型
 */
tNCI_RF_INTERFACE rw_utils_get_rf_interface_from_protocol(tNCI_RF_PROTOCOL protocol) {
     switch(protocol) {
        case NCI_RF_PROTOCOL_ISO_DEP:
            return NCI_RF_INTERFACE_ISO_DEP;
        case NCI_RF_PROTOCOL_M1:
            return NCI_RF_INTERFACE_TAG_CMD;
        case NCI_RF_PROTOCOL_NFC_DEP:
            return NCI_RF_INTERFACE_NFC_DEP;
        default:
            return NCI_RF_INTERFACE_FRAME;
    }
}

static void copy_tag_type(tNCI_RW_TAG *p_tag, uint8_t from_index, tNCI_RW_TAG_TYPE type) {
    p_tag->disc_ids[p_tag->tech_size] = p_tag->disc_ids[from_index];
    p_tag->protocols[p_tag->tech_size] = p_tag->protocols[from_index];
    p_tag->interfaces[p_tag->tech_size] = p_tag->interfaces[from_index];
    p_tag->tag_types[p_tag->tech_size] = type;
    p_tag->tech_size++;
}
#if IS_FEATURE_ON(NCI_FEATURE_NDEF_EXT)
/**
 * @brief 读取并添加NDEF类型到当前卡片
 *
 * @note 如果卡片没有NDEF数据但是支持格式化成NDEF会添加NCI_RW_TAG_TYPE_NDEF_FORMATABLE
 *
 * @param[out] p_ndef_rsp 用于接收读取到的NDEF数据，函数返回NCI_STATUS_OK时有效
 * @param[out] p_ndef_type 用于接收NDEF类型，函数返回NCI_STATUS_OK时有效
 * @param[out] p_ndef_mode 用于接收NDEF模式，函数返回NCI_STATUS_OK时有效
 *
 * @return 读取NDEF数据成功返回NCI_STATUS_OK，反之返回其他错误码
 */
tNCI_STATUS nfa_rw_ndef_find_and_add_tech(tNCI_RSP *p_ndef_rsp, tNCI_RW_NDEF_TYPE *p_ndef_type, tNCI_RW_NDEF_MODE *p_ndef_mode) {
    if (!p_ndef_rsp || !p_ndef_type || !p_ndef_mode) {
        NFCLOG_E("invalid param");
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    tNCI_STATUS ret = nfa_rw_request_lock();
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("nfa_rw_request_lock failed, ret=%d", ret);
        return ret;
    }
    tNCI_RW_TAG *p_tag = nfa_rw_get_activated_tag();
    if (!p_tag) {
        NFCLOG_E("no tag activated");
        ret = NCI_STATUS_EXT_TAG_LOST;
        goto unlock;
    }

    bool found_ndef_formattable = false;
    uint8_t ndef_formattable_index = 0;

    for (uint8_t i = 0; i < p_tag->tech_size; i++) {
        bool skip_check = false;
        for (uint8_t j = 0; j < i; j++) {
            if (p_tag->disc_ids[j] == p_tag->disc_ids[i]) {
                // 这个Discover ID已经检查过了
                skip_check = true;
                break;
            }
        }
        if (skip_check) {
            continue;
        }
        ret = nfa_rw_connect(i);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("nfa_rw_connect failed, ret=%d", ret);
            goto unlock;
        }
        if (!found_ndef_formattable) {
            ret = nfa_rw_is_ndef_formatable();
            if (ret == NCI_STATUS_OK) {
                found_ndef_formattable = true;
                ndef_formattable_index = i;
            }
            nfa_rw_reconnect();
        }
        tNCI_RW_NDEF_INFO ndef_info = {0};
        ret = nfa_rw_ndef_detect(&ndef_info);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("nfa_rw_ndef_detect failed, ret=%d", ret);
            if (ret == NCI_STATUS_EXT_TAG_LOST) {
                // 卡片已丢失，终止检测
                break;
            }
            continue; // 当前技术上未检测到NDEF数据，尝试下一个技术
        }
        *p_ndef_type = nfa_rw_ndef_get_type(p_tag->protocols[i], p_tag->tag_types[i]);
        *p_ndef_mode = ndef_info.mode;
        bool add_ndef_tech = true;
        if (ndef_info.curr_size > 0) {
            ret = nfa_rw_ndef_read(p_ndef_rsp);
            if (ret != NCI_STATUS_OK) {
                NFCLOG_E("nfa_rw_ndef_read failed, ret=%d", ret);
                add_ndef_tech = false;
            }
            nfa_rw_reconnect();
        }
        if (add_ndef_tech) {
            // 添加NDEF Tech
            found_ndef_formattable = false;
            copy_tag_type(p_tag, i, NCI_RW_TAG_TYPE_NDEF);
        }
        break;
    }
    if (found_ndef_formattable) {
        copy_tag_type(p_tag, ndef_formattable_index, NCI_RW_TAG_TYPE_NDEF_FORMATABLE);
    }
unlock:
    nfa_rw_release_lock();
    return ret;
}
#endif // IS_FEATURE_ON(NCI_FEATURE_NDEF_EXT)

#if IS_FEATURE_ON(NCI_FEATURE_RW_T1T)
extern tNCI_RW_TAG_API g_rw_t1t_api;
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_T1T)
#if IS_FEATURE_ON(NCI_FEATURE_RW_T2T)
extern tNCI_RW_TAG_API g_rw_t2t_api;
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_T2T)
#if IS_FEATURE_ON(NCI_FEATURE_RW_T3T)
extern tNCI_RW_TAG_API g_rw_t3t_api;
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_T3T)
#if IS_FEATURE_ON(NCI_FEATURE_RW_T4T)
extern tNCI_RW_TAG_API g_rw_t4t_api;
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_T4T)
#if IS_FEATURE_ON(NCI_FEATURE_RW_T5T)
extern tNCI_RW_TAG_API g_rw_t5t_api;
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_T5T)
#if IS_FEATURE_ON(NCI_FEATURE_RW_M1)
extern tNCI_RW_TAG_API g_rw_m1_api;
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_M1)
#if IS_FEATURE_ON(NCI_FEATURE_RW_CI)
extern tNCI_RW_TAG_API g_rw_ci_api;
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_CI)
/**
 * @brief 获取tag对应的操作api
 *
 * @param p_tag tag指针
 *
 * @return 当当前tag协议类型不支持时返回NULL，否则返回对应的tag操作api
 */
tNCI_RW_TAG_API* rw_utils_get_tag_api(tNCI_RW_TAG *p_tag) {
    if (!p_tag) {
        NFCLOG_E("Invalid tag");
        return NULL;
    }
    tNCI_RF_PROTOCOL protocol = p_tag->protocols[p_tag->index];
    tNCI_RW_TAG_API *p_api = NULL;
    switch (protocol)
    {
#if IS_FEATURE_ON(NCI_FEATURE_RW_T1T)
    case NCI_RF_PROTOCOL_T1T:
        p_api = &g_rw_t1t_api;
        break;
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_T1T)
#if IS_FEATURE_ON(NCI_FEATURE_RW_T2T)
    case NCI_RF_PROTOCOL_T2T:
        p_api = &g_rw_t2t_api;
        break;
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_T2T)
#if IS_FEATURE_ON(NCI_FEATURE_RW_T3T)
    case NCI_RF_PROTOCOL_T3T:
        p_api = &g_rw_t3t_api;
        break;
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_T3T)
#if IS_FEATURE_ON(NCI_FEATURE_RW_T4T)
    case NCI_RF_PROTOCOL_ISO_DEP:
        p_api = &g_rw_t4t_api;
        break;
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_T4T)
#if IS_FEATURE_ON(NCI_FEATURE_RW_T5T)
    case NCI_RF_PROTOCOL_T5T:
        p_api = &g_rw_t5t_api;
        break;
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_T5T)
    // case NCI_RF_PROTOCOL_KOVIO:
    //     break;
#if IS_FEATURE_ON(NCI_FEATURE_RW_M1)
    case NCI_RF_PROTOCOL_M1:
        p_api = &g_rw_m1_api;
        break;
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_M1)
#if IS_FEATURE_ON(NCI_FEATURE_RW_CI)
    case NCI_RF_PROTOCOL_UNDETERMINED:
        if (p_tag->tag_types[p_tag->index] == NCI_RW_TAG_TYPE_B) {
            p_api = &g_rw_ci_api;
        } else {
            NFCLOG_E("undetermined protocol but not CI card, type: %d, not support", p_tag->tag_types[p_tag->index]);
        }
        break;
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_CI)
    default:
        NFCLOG_E("curr protocol: 0x%02X not support now", protocol);
        break;
    }
    return p_api;
}
/**
 * @brief dump tag信息
 *
 * @param p_tag tag指针
 * @param fd 文件描述符
 */
void rw_utils_dump_tag(int fd, const tNCI_RW_TAG *p_tag) {
    if (!p_tag) {
        NFCLOG_E("Invalid tag");
        return;
    }
    size_t str_cap = 200;
    char *str = (char*)osi_calloc(str_cap);
    if (!str) {
        NFCLOG_E("Failed to allocate memory");
        return;
    }
    osi_dump(fd, "Connected tech index: %d", p_tag->index);
    osi_dump(fd, "Tech count: %d", p_tag->tech_size);

    bytes_to_hex(p_tag->uid, p_tag->uid_len, str);
    osi_dump(fd, "UID: 0x%s", str);
    int offset = 0;

    osi_memset_s(str, str_cap, 0, str_cap);
    for (int i = 0; i < p_tag->tech_size; i++) {
        offset += snprintf(str + offset, str_cap, "%d,", p_tag->disc_ids[i]);
    }
    osi_dump(fd, "Discovery IDs: %s", str);
    osi_memset_s(str, str_cap, 0, str_cap);
    offset = 0;
    for (int i = 0; i < p_tag->tech_size; i++) {
        offset += snprintf(str + offset, str_cap, "%d,", p_tag->protocols[i]);
    }
    osi_dump(fd, "Protocols: %s", str);
    osi_memset_s(str, str_cap, 0, str_cap);
    offset = 0;
    for (int i = 0; i < p_tag->tech_size; i++) {
        offset += snprintf(str + offset, str_cap, "%d,", p_tag->interfaces[i]);
    }
    osi_dump(fd, "Interfaces: %s", str);
    osi_memset_s(str, str_cap, 0, str_cap);
    offset = 0;
    for (int i = 0; i < p_tag->tech_size; i++) {
        offset += snprintf(str + offset, str_cap, "%d,", p_tag->tag_types[i]);
    }
    osi_dump(fd, "TagTypes: %s", str);
    osi_memset_s(str, str_cap, 0, str_cap);
    offset = 0;
    for (int i = 0; i < p_tag->tech_size; i++) {
        const tNCI_RW_POLL_DATA *poll_data = &p_tag->poll_data[i];
        offset += bytes_to_hex(poll_data->data, poll_data->len, str + offset);
        str[offset-1] = ',';
    }
    osi_dump(fd, "Poll Data: %s", str);
    osi_memset_s(str, str_cap, 0, str_cap);
    offset = 0;
    for (int i = 0; i < p_tag->tech_size; i++) {
        const tNCI_RW_ACT_DATA *act_data = &p_tag->act_data[i];
        offset += bytes_to_hex(act_data->data, act_data->len, str + offset);
        str[offset-1] = ',';
    }
    osi_dump(fd, "Act Data: %s", str);
    osi_free(str);
}

static unsigned int tags_ones32(unsigned int x) {
    /* 32-bit recursive reduction using SWAR...
        but first step is mapping 2-bit values
        into sum of 2 1-bit values in sneaky way
    */
    x -= ((x >> 1) & 0x55555555);
    x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
    x = (((x >> 4) + x) & 0x0f0f0f0f);
    x += (x >> 8);
    x += (x >> 16);
    return (x & 0x0000003f);
}
/**
 * @brief 计算x的log2
 */
uint32_t rw_utils_tags_log2(uint32_t x) {
    x |= (x >> 1);
    x |= (x >> 2);
    x |= (x >> 4);
    x |= (x >> 8);
    x |= (x >> 16);
    return (tags_ones32(x) - 1);
}

#endif // IS_FEATURE_ON(NCI_FEATURE_RW)
